// Copyright (c) 2011 Blue Onion Software, All rights reserved
using System;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Web.Caching;
using System.Web.Hosting;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace BlueOnionSoftware.Bloget
{
    internal class LogView : View
    {
        private DropDownList _fileList;
        private DropDownList _pageSizeSelector;
        private HiddenField _selected;

        private bool _disposed;
        private const string FieldCode = "Code";
        private const string FieldTime = "Time";
        private const string FieldId = "ID";
        private const string FieldReferer = "Referer";
        private const string FieldDescription = "Description";

        private const string LogPageSize = "log_page_size";

        internal LogView(Bloget blogetArg)
            : base(blogetArg)
        {
        }

        protected override void Dispose(bool managed)
        {
            try
            {
                if (_disposed == false)
                {
                    _disposed = true;

                    if (managed)
                    {
                        if (_fileList != null)
                        {
                            _fileList.Dispose();
                        }

                        if (_pageSizeSelector != null)
                        {
                            _pageSizeSelector.Dispose();
                        }

                        if (_selected != null)
                        {
                            _selected.Dispose();
                        }
                    }
                }
            }

            finally
            {
                base.Dispose(managed);
            }
        }

        protected override string RootClassId()
        {
            return "log-view";
        }

        protected override void ShowView()
        {
            if (Bloget.IsAdministrator == false)
            {
                var passwordForm = new PasswordView(Bloget);
                passwordForm.Show();
                return;
            }

            MainMenu.ShowMenu(Bloget);

            const string listOfLogFilesKey = "LogFiles";
            var files = Bloget.Page.Session[listOfLogFilesKey] as string[];

            if (files == null)
            {
                var appFolder = HostingEnvironment.MapPath(Log.VirtualLogFolder);
                files = Directory.GetFiles(appFolder, Log.LogFilePattern, SearchOption.TopDirectoryOnly);
                Array.Sort(files, new ReverseCompare());

                Bloget.Page.Cache.Insert(listOfLogFilesKey, files, null,
                                         DateTime.Now.AddMinutes(1d), Cache.NoSlidingExpiration);
            }

            _fileList = new DropDownList {AutoPostBack = true, Width = Unit.Point(144)};
            _fileList.Items.Add(new ListItem("Pick File"));
            _fileList.SelectedIndexChanged += OnSelect;

            foreach (var file in files)
            {
                var item = new ListItem(Path.GetFileName(file), file);
                _fileList.Items.Add(item);
            }

            Bloget.Controls.Add(_fileList);
            Bloget.Controls.Add(new LiteralControl("&nbsp;" + Environment.NewLine));

            _pageSizeSelector = new DropDownList {Width = Unit.Point(50)};
            _pageSizeSelector.Items.Add("10");
            _pageSizeSelector.Items.Add("20");
            _pageSizeSelector.Items.Add("50");
            _pageSizeSelector.Items.Add("100");
            _pageSizeSelector.SelectedValue = (string) (Bloget.Page.Session[LogPageSize] ?? "10");
            Bloget.Page.Session[LogPageSize] = _pageSizeSelector.SelectedItem.Value;
            _pageSizeSelector.AutoPostBack = true;
            Bloget.Controls.Add(_pageSizeSelector);

            _selected = new HiddenField();
            Bloget.Controls.Add(_selected);
            Bloget.Controls.Add(new LiteralControl(Environment.NewLine + "<br/><br/>" + Environment.NewLine));
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private void OnSelect(object sender, EventArgs ea)
        {
            try
            {
                var eventView = HostingEnvironment.Cache[_fileList.SelectedValue] as DataView;

                if (eventView == null)
                {
                    using (var events = new DataTable("Events"))
                    {
                        events.Locale = CultureInfo.InvariantCulture;
                        events.Columns.Add(FieldCode, typeof (int));
                        events.Columns.Add(FieldTime, typeof (string));
                        events.Columns.Add(FieldId, typeof (string));
                        events.Columns.Add(FieldReferer, typeof (string));
                        events.Columns.Add(FieldDescription, typeof (string));

                        using (var file = FileUtilities.OpenRead(_fileList.SelectedValue))
                        {
                            using (var reader = new StreamReader(file))
                            {
                                var separators = new char[] {};

                                while (reader.EndOfStream == false)
                                {
                                    var line = reader.ReadLine();
                                    if (line != null)
                                    {
                                        var parts = line.Split(separators, 5, StringSplitOptions.RemoveEmptyEntries);

                                        if (parts.Length != 5)
                                        {
                                            continue;
                                        }

                                        int code;
                                        if (int.TryParse(parts[0], out code) == false)
                                        {
                                            continue;
                                        }

                                        DateTime date;
                                        if (DateTime.TryParse(parts[1], out date) == false)
                                        {
                                            continue;
                                        }

                                        var row = events.NewRow();
                                        row[0] = code;
                                        row[1] = date.ToString("T", DateTimeFormatInfo.InvariantInfo);
                                        row[2] = parts[2];
                                        row[3] = parts[3];
                                        row[4] = parts[4];
                                        events.Rows.Add(row);
                                    }
                                }
                            }
                        }

                        eventView = events.DefaultView;

                        using (var cd = new CacheDependency(_fileList.SelectedValue))
                        {
                            HostingEnvironment.Cache.Insert(_fileList.SelectedValue, eventView, cd,
                                                            Cache.NoAbsoluteExpiration, new TimeSpan(0, 5, 0),
                                                            CacheItemPriority.Low, null);
                        }
                    }
                }

                BuildGrid(eventView);
            }

            catch (Exception ex)
            {
                Log.Exception(Bloget, "LogView.OnSelect", ex);
                Bloget.Controls.Add(new LiteralControl(ex.ToString()));
            }
        }

        private void BuildGrid(DataView events)
        {
            var gridView = new GridView();

            // IMPORTANT - add to control group before setting properties to
            // avoid a page fault.
            Bloget.Controls.Add(gridView);

            gridView.DataSource = events;
            gridView.CellPadding = 2;
            gridView.AllowSorting = true;
            gridView.Sorting += OnSort;
            gridView.AllowPaging = true;
            gridView.PageSize = Convert.ToInt32(_pageSizeSelector.SelectedValue, CultureInfo.CurrentCulture);
            gridView.PagerSettings.Position = PagerPosition.TopAndBottom;
            gridView.PageIndexChanging += OnPageIndexChanging;
            gridView.RowCreated += OnRowCreated;
            gridView.DataBind();
        }

        private static void OnRowCreated(object sender, GridViewRowEventArgs e)
        {
            if (e != null)
            {
                var dataRowView = e.Row.DataItem as DataRowView;

                if (dataRowView == null)
                {
                    return;
                }

                int code;

                if (int.TryParse(dataRowView.Row.ItemArray[0].ToString(), out code) == false)
                {
                    code = 0;
                }

                Color[] colors =
                    {
                        Color.Empty,
                        Color.FromArgb(0xFF6060),
                        Color.FromArgb(0xAAAAFF),
                        Color.FromArgb(0x60FF60),
                        Color.FromArgb(0xFFFF60)
                    };

                e.Row.BackColor = colors[(code/100)%colors.Length];
            }
        }

        private void OnSort(object sender, GridViewSortEventArgs ea)
        {
            const string sortKey = "log_sort_direction";

            var gridView = (GridView) sender;
            if (gridView != null)
            {
                var dataView = (DataView) gridView.DataSource;
                if (ea != null)
                {
                    ea.SortDirection = (SortDirection) (Bloget.Page.Session[sortKey] ?? SortDirection.Descending);
                    dataView.Sort = ea.SortExpression + ((ea.SortDirection == SortDirection.Ascending) ? " ASC" : " DESC");
                }
            }

            if (ea != null)
            {
                Bloget.Page.Session[sortKey] = (ea.SortDirection == SortDirection.Ascending)
                    ? SortDirection.Descending
                    : SortDirection.Ascending;
            }

            if (gridView != null)
            {
                gridView.DataBind();
            }
        }

        private static void OnPageIndexChanging(object sender, GridViewPageEventArgs ea)
        {
            var gridView = (GridView) sender;
            if (gridView != null)
            {
                if (ea != null)
                {
                    gridView.PageIndex = ea.NewPageIndex;
                }
                gridView.DataBind();
            }
        }
    }
}